﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using QFrameworkOne.Diagnostics;

namespace QFrameworkOne.Module {
    /// <summary>
    /// QData文件解析模块
    /// </summary>
    public class QData : QComponentBase, IQMoudule {
        /// <summary>
        /// 文件名
        /// </summary>
        public string FileName = "";

        private Dictionary<string, QDataSection> QSections;
        private Encoding FileEncoding = Encoding.Default;

        private QDebug Qdb = new QDebug() {
            CodeLocation = "QFrameworkOne.Module.QData",
            ConsoleOutput = true
        };

        /// <summary>
        /// 所有节点，只读属性
        /// </summary>
        public Dictionary<string, QDataSection> Sections {
            get { return QSections; }
        }

        string IQMoudule.Module_Name => "QData";

        string IQMoudule.Module_Author => "DealiAxy";

        string IQMoudule.Module_Mail => "admin@deali.cn";

        string IQMoudule.Module_Website => "http://blog.deali.cn";

        string IQMoudule.Module_Description => "QData文件解析模块";

        QComponentVersion IQMoudule.Module_Version => new QComponentVersion()
            {Major = 1, Minor = 5, Update = 7, Label = QComponentVersionLabel.Beta};

        /// <summary>
        /// Sections 索引器 Dictionary(string, QDataSection)。具备快捷读取和添加、修改功能。
        /// </summary>
        /// <param name="section">节点名称</param>
        /// <returns>QDataSection对象</returns>
        public QDataSection this[string section] {
            get {
                Qdb.CodeFunction = "[this]get";
                Qdb.LogType = QDebugLogType.QDebug;

                if (!QSections.ContainsKey(section)) {
                    Qdb.Log("尝试访问 {0} Section，节点不存在，自动创建", section);
                    QDataSection ds = new QDataSection(section);
                    QSections.Add(section, ds);
                }

                return QSections[section];
            }
            set {
                Qdb.CodeFunction = "[this]set";
                Qdb.LogType = QDebugLogType.QDebug;

                if (QSections.ContainsKey(section))
                    QSections[section] = value;
                else {
                    Qdb.Log("尝试访问 {0} Section，节点不存在，自动创建", section);
                    QSections.Add(section, value);
                }
            }
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        /// <param name="fileName"></param>
        public QData(string fileName) : this(fileName, Encoding.Default) {
        }

        /// <summary>
        /// 指定文件编码的构造函数
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="encoding"></param>
        public QData(string fileName, Encoding encoding) {
            fileName = Path.GetFullPath(fileName);

            CodeVersion.Major = 1;
            CodeVersion.Minor = 3;
            CodeVersion.Update = 16;
            CodeVersion.Label = QComponentVersionLabel.Beta;

            Qdb.Log(string.Format("QData Class instantiate. Version: {0}", CodeVersion.ToString()),
                QDebugLogType.QDebug, "QData");
            Qdb.Log(string.Format("Open File: {0}", fileName), QDebugLogType.QDebug, "QData");

            CodeLocation = this.ToString();
            FileName = fileName;
            if (!Directory.Exists(Path.GetDirectoryName(fileName))) {
                Qdb.Error(string.Format("路径 {0} 不存在，没法玩了。", Path.GetDirectoryName(fileName)), QDebugErrorType.QDebug,
                    "QData");
                QSections = new Dictionary<string, QDataSection>();
                throw new DirectoryNotFoundException(string.Format("路径 {0} 不存在，没法玩了。",
                    Path.GetDirectoryName(fileName)));
            }

            if (!File.Exists(fileName)) {
                Qdb.Error(string.Format("文件 {0} 不存在，创建新文件。", fileName), QDebugErrorType.QDebug, "QData");
                QSections = new Dictionary<string, QDataSection>();
                return;
            }

            FileEncoding = encoding;
            QSections = LoadAllSection();
        }

        /// <summary>
        /// 默认析构函数，销毁对象时自动保存数据
        /// </summary>
        ~QData() {
            Save();
        }

        /// <summary>
        /// 关闭文件并写入更改，QData具有自动保存功能，即使不调用这个方法也能自动保存
        /// </summary>
        public void Close() {
            Save();
        }

        /// <summary>
        /// 关闭文件并且释放资源
        /// </summary>
        public void Dispose() {
            QSections.Clear();
        }

        /// <summary>
        /// 保存所有更改，同时会关闭文件。（旧版本兼容）
        /// </summary>
        public void Save() {
            Qdb.Log(string.Format("Save Data.覆盖保存所有数据，Section数量：{0}", QSections.Count.ToString()), QDebugLogType.QDebug,
                "Save");

            StreamWriter sW = new StreamWriter(FileName, false, FileEncoding);
            foreach (KeyValuePair<string, QDataSection> p in QSections) {
                Qdb.Log(string.Format("写入节点：{0}", p.Key), QDebugLogType.QDebug, "Save");
                sW.WriteLine("[{0}]", p.Key);
                foreach (KeyValuePair<string, string> pp in p.Value.Keys) {
                    //替换掉换行
                    string value = pp.Value;
                    if (pp.Value.Contains(Environment.NewLine))
                        value = value.Replace(Environment.NewLine, @"<br/>");

                    sW.WriteLine("{0}={1}", pp.Key, value);
                }
            }

            sW.Close();
        }

        /// <summary>
        /// 读取所有节点
        /// </summary>
        /// <returns></returns>
        public List<QDataSection> GetAllSections() {
            List<QDataSection> sections = new List<QDataSection>();
            foreach (KeyValuePair<string, QDataSection> p in QSections) {
                sections.Add(p.Value);
            }

            return sections;
        }

        /// <summary>
        /// 读取所有节点(字符串)
        /// </summary>
        /// <returns></returns>
        public string[] GetAllSectionsArray() {
            List<QDataSection> sections = GetAllSections();
            string[] array = new string[sections.Count];
            for (int i = 0; i < sections.Count; i++) {
                array[i] = sections[i].Name;
            }

            return array;
        }

        /// <summary>
        /// 读取节点下的所有键
        /// </summary>
        /// <param name="strSection"></param>
        /// <returns></returns>
        public Dictionary<string, string> GetAllKeys(string strSection) {
            return QSections[strSection].Keys;
        }

        /// <summary>
        /// 读取节点下的所有键名称(字符串)
        /// </summary>
        /// <param name="strSection"></param>
        /// <returns></returns>
        public string[] GetAllKeysArray(string strSection) {
            string[] array = new string[QSections[strSection].Keys.Count];
            int i = 0;
            foreach (KeyValuePair<string, string> p in QSections[strSection].Keys) {
                array[i] = p.Key;
                i++;
            }

            return array;
        }

        /// <summary>
        /// 读取数据
        /// </summary>
        /// <param name="strSection">节点名称</param>
        /// <param name="strKey">是否成功</param>
        /// <param name="strDefault">默认值 - 读取不到数据时返回默认值</param>
        /// <returns></returns>
        public string GetValue(string strSection, string strKey, string strDefault = "") {
            string result = QSections[strSection].Keys[strKey];
            return result == "" ? strDefault : result;
        }

        /// <summary>
        /// 删除节点
        /// </summary>
        /// <param name="strSection">节点名称</param>
        /// <returns>是否成功</returns>
        public bool RemoveSection(string strSection) {
            return QSections.Remove(strSection);
        }

        /// <summary>
        /// 删除指定键
        /// </summary>
        /// <param name="strSection">节点名称</param>
        /// <param name="strKeyName">键名称</param>
        /// <returns>是否成功</returns>
        public bool RemoveKey(string strSection, string strKeyName) {
            return QSections[strSection].Keys.Remove(strKeyName);
        }

        /// <summary>
        /// 插入节点，一经执行将立即写入到文件中，谨慎使用。不需要再使用Close关闭QData
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool InsertSection(QDataSection param) {
            if (QSections.ContainsKey(param.Name))
                return false;
            else {
                QSections.Add(param.Name, param);
                StreamWriter sW = new StreamWriter(FileName, true, Encoding.Default);
                sW.WriteLine("[{0}]", param.Name);
                foreach (KeyValuePair<string, string> p in param.Keys) {
                    sW.WriteLine("{0}={1}", p.Key, p.Value);
                }

                sW.Close();
                return true;
            }
        }

        /// <summary>
        /// 修改数据，如果不存在的话会创建新的Section
        /// </summary>
        /// <param name="strSection">节点</param>
        /// <param name="strKey">键值</param>
        /// <param name="strValue">数据</param>
        public bool ModifyValue(string strSection, string strKey, string strValue) {
            Qdb.Log(string.Format("修改数据 节点：{0} 键：{1} 值：{2}", strSection, strKey, strValue), QDebugLogType.Info,
                "ModifyValue");
            if (QSections.ContainsKey(strSection)) {
                Qdb.Log("节点已经存在", QDebugLogType.QDebug, "ModifyValue");
                QSections[strSection].Keys[strKey] = strValue;
            }
            else {
                Qdb.Log("新节点", QDebugLogType.QDebug, "ModifyValue");
                QDataSection qds = new QDataSection {
                    Name = strSection
                };
                qds.Keys.Add(strKey, strValue);
                QSections.Add(strSection, qds);
            }

            return true;
        }

        /// <summary>
        /// 修改数据，如果不存在的话会创建新的Section
        /// </summary>
        /// <param name="param">QDataSection实例</param>
        /// <returns>是否成功</returns>
        public bool ModifyValue(QDataSection param) {
            if (QSections.ContainsKey(param.Name))
                QSections[param.Name] = param;
            else
                QSections.Add(param.Name, param);
            return true;
        }


        /// <summary>
        /// 检查QData文件是否包含特定节点
        /// </summary>
        /// <param name="strSection"></param>
        /// <returns>结果</returns>
        public bool ContainSection(string strSection) {
            return QSections.ContainsKey(strSection);
        }

        /// <summary>
        /// 加载所有节点
        /// </summary>
        /// <returns></returns>
        private Dictionary<string, QDataSection> LoadAllSection() {
            Dictionary<string, QDataSection> sections = new Dictionary<string, QDataSection>();

            using (FileStream fS = new FileStream(FileName, FileMode.OpenOrCreate)) {
                using (StreamReader sR = new StreamReader(fS, FileEncoding)) {
                    if (fS.Length == 0) //如果文件大小为0就返回空的Section列表
                        return new Dictionary<string, QDataSection>();

                    QDataSection qSection = new QDataSection("");
                    string line = "";
                    while (!sR.EndOfStream) {
                        line = sR.ReadLine();
                        if (line.Length > 0) {
                            if (line[0] == '[') {
                                if (qSection.Name.Length > 0) {
                                    sections.Add(qSection.Name, qSection);
                                }

                                try {
                                    string sectionNane = line.Substring(1, line.IndexOf(']') - 1);
                                    qSection = new QDataSection();
                                    qSection.Name = sectionNane;
                                }
                                catch (Exception ex) {
                                    Console.WriteLine(ex.Message);
                                }
                            }
                            else if (line.Contains('=')) {
                                string key = line.Substring(0, line.IndexOf('='));
                                string value = line.Substring(line.IndexOf('=') + 1);

                                //换行替换
                                if (value.Contains(@"<br/>"))
                                    value = value.Replace(@"<br/>", Environment.NewLine);

                                qSection.Keys.Add(key, value);
                            }
                        }
                        else
                            continue;
                    }

                    if (qSection.Name.Length > 0) //节点名不为空才能添加进去
                    {
                        sections.Add(qSection.Name, qSection);
                    }

                    return sections;
                }
            }
        }
    }

    /// <summary>
    /// QData数据文件的节点
    /// </summary>
    public class QDataSection : QComponentBase {
        /// <summary>
        /// 节点内包含的键值
        /// </summary>
        public Dictionary<string, string> Keys = new Dictionary<string, string>();

        /// <summary>
        /// 节点名称
        /// </summary>
        public string Name = "";

        /// <summary>
        /// Keys 索引器 Dictionary(string, string)
        /// </summary>
        /// <param name="key">Key名称</param>
        /// <returns>Key值</returns>
        public string this[string key] {
            get => Keys.ContainsKey(key) ? Keys[key] : "";

            set {
                if (Keys.ContainsKey(key))
                    Keys[key] = value;
                else
                    Keys.Add(key, value);
            }
        }

        /// <summary>
        /// 节点内的键数量
        /// </summary>
        public int Count {
            get { return Keys.Count; }
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public QDataSection() {
            CodeVersion.Major = 1;
            CodeVersion.Minor = 1;
            CodeVersion.Update = 2;
            CodeVersion.Label = QComponentVersionLabel.Beta;
        }

        /// <summary>
        /// 新建节点的同时指点节点名称
        /// </summary>
        /// <param name="SectionName"></param>
        public QDataSection(string SectionName)
            : this() {
            Name = SectionName;
        }
    }
}